package com.weixin.utils;

import java.security.MessageDigest;
import java.security.NoSuchAlgorithmException;
import java.util.Arrays;
import java.util.HashSet;
import java.util.List;
import java.util.Map;
import java.util.Set;

import org.apache.commons.lang3.StringUtils;
import org.slf4j.Logger;
import org.slf4j.LoggerFactory;

import com.weixin.config.WxConfig;
import com.weixin.core.TokenFactory;

/**
 * 类描述：微信web授权<br>
 * 创建人：邓强   <br>
 * 创建时间：2017年10月30日 上午11:09:13    <br> 
 * 修改人：  <br>
 * 修改时间：2017年10月30日 上午11:09:13   <br>  
 * 修改备注：     <br>
 * @version   V1.0
 */
@SuppressWarnings("unchecked")
public class WxWeb {
	private static Logger log=LoggerFactory.getLogger(WxWeb.class);
	
	/**
	 * 验证服务器地址的有效性(签名)<br>
	 * <br>  
	 * 创建人：邓强   <br>
	 * 创建时间：2017年10月30日 上午11:08:46    <br> 
	 * 修改人：  <br>
	 * 修改时间：2017年10月30日 上午11:08:46   <br>  
	 * 修改备注：     <br> 
	 * @param signature	签名
	 * @param timestamp	时间戳
	 * @param nonce		随机数
	 * @return
	 */
	public static boolean check(String signature, String timestamp, String nonce) {
		try{
			if(signature==null || timestamp==null || nonce==null){
				return false;
			}
			
			String[] arrA=new String[]{WxConfig.token, timestamp, nonce};
			Arrays.sort(arrA);
			StringBuilder sb=new StringBuilder();
			for(int i=0;i<arrA.length;i++){
				sb.append(arrA[i]);
			}
			
			MessageDigest md=MessageDigest.getInstance("SHA-1");
			byte[] arrB=md.digest(sb.toString().getBytes());
			char[] arrC=new char[]{'0','1','2','3','4','5','6','7','8','9','a','b','c','d','e','f'};
			String signatureTemp="";
			for(int i=0;i<arrB.length;i++){
				char[] arrCTemp=new char[2];
				arrCTemp[0]=arrC[(arrB[i]>>>4) & 0X0F];
				arrCTemp[1]=arrC[arrB[i] & 0X0F];
				String str=new String(arrCTemp);
				
				signatureTemp=signatureTemp+str;
			}
			
			return signature.equals(signatureTemp);
		} catch(NoSuchAlgorithmException e){
			log.error("", e);
		}
		
		return false;
	}
	
	/**
	 * 获取授权url<br>
	 * <br>  
	 * 创建人：邓强   <br>
	 * 创建时间：2017年10月30日 上午11:10:44    <br> 
	 * 修改人：  <br>
	 * 修改时间：2017年10月30日 上午11:10:44   <br>  
	 * 修改备注：     <br> 
	 * @param scope		snsapi_base、snsapi_userinfo 
	 * @param redirectUri	重定向地址
	 * @param state	额外参数
	 * @return
	 */
	
	public static String autlUrl(String scope, String redirectUri, String state){
		WxConfig wxConfig = TokenFactory.getDefaultWxConfigs();
		return autlUrl(wxConfig, scope, redirectUri, state);
	}
	
	/**
	 * 获取授权url<br>
	 * <br>  
	 * 创建人：邓强   <br>
	 * 创建时间：2017年10月30日 上午11:10:58    <br> 
	 * 修改人：  <br>
	 * 修改时间：2017年10月30日 上午11:10:58   <br>  
	 * 修改备注：     <br> 
	 * @param wxConfig
	 * @param scope		snsapi_base、snsapi_userinfo 
	 * @param redirectUri	重定向地址
	 * @param state		额外参数
	 * @return
	 */
	public static String autlUrl(WxConfig wxConfig, String scope, String redirectUri, String state){
		if(StringUtils.isBlank(state)){
			state = "STATE";
		}
		
		String requestUrl="https://open.weixin.qq.com/connect/oauth2/authorize"
				+"?appid="+WxHttp.enStr(wxConfig.getAppId())
				+"&redirect_uri="+WxHttp.enStr(redirectUri)
				+"&response_type=code"
				+"&scope="+WxHttp.enStr(scope)
				+"&state="+WxHttp.enStr(state)
				+"#wechat_redirect";
		
		return requestUrl;
	}
	
	/**
	 * 通过code换取网页授权access_token<br>
	 * <br>  
	 * 创建人：邓强   <br>
	 * 创建时间：2017年10月30日 上午11:11:19    <br> 
	 * 修改人：  <br>
	 * 修改时间：2017年10月30日 上午11:11:19   <br>  
	 * 修改备注：     <br> 
	 * @param code
	 * @return
	 */
	public static Map<String, Object> accessToken(String code){
		WxConfig wxConfig = TokenFactory.getDefaultWxConfigs();
		return accessToken(wxConfig, code);
	}
	
	/**
	 * 通过code换取网页授权access_token<br>
	 * <br>  
	 * 创建人：邓强   <br>
	 * 创建时间：2017年10月30日 上午11:11:30    <br> 
	 * 修改人：  <br>
	 * 修改时间：2017年10月30日 上午11:11:30   <br>  
	 * 修改备注：     <br> 
	 * @param wxConfig
	 * @param code
	 * @return
	 */
	public static Map<String, Object> accessToken(WxConfig wxConfig, String code){
		try {
			String requestUrl="https://api.weixin.qq.com/sns/oauth2/access_token"
					+"?appid="+WxHttp.enStr(wxConfig.getAppId())
					+"&secret="+WxHttp.enStr(wxConfig.getAppsecret())
					+"&code="+code
					+"&grant_type=authorization_code";
			
			String resStr=WxHttp.httpsRequest(requestUrl, null);
			
			return WxJson.fromJson(resStr, Map.class);
		} catch (Exception e) {
			log.error("", e);
		}
		
		return null;
	}
	
	/**
	 * 刷新access_token<br>
	 * <br>  
	 * 创建人：邓强   <br>
	 * 创建时间：2017年10月30日 上午11:11:58    <br> 
	 * 修改人：  <br>
	 * 修改时间：2017年10月30日 上午11:11:58   <br>  
	 * 修改备注：     <br> 
	 * @param appid
	 * @param refreshToken
	 * @return
	 */
	public static Map<String, Object> refreshToken(String appid, String refreshToken){
		WxConfig wxConfig = TokenFactory.getDefaultWxConfigs();
		return refreshToken(wxConfig, refreshToken);
	}
	
	/**
	 * 刷新access_token<br>
	 * <br>  
	 * 创建人：邓强   <br>
	 * 创建时间：2017年10月30日 上午11:12:17    <br> 
	 * 修改人：  <br>
	 * 修改时间：2017年10月30日 上午11:12:17   <br>  
	 * 修改备注：     <br> 
	 * @param wxConfig
	 * @param refreshToken
	 * @return
	 */
	public static Map<String, Object> refreshToken(WxConfig wxConfig, String refreshToken){
		try {
			String requestUrl="https://api.weixin.qq.com/sns/oauth2/refresh_token"
					+"?appid="+WxHttp.enStr(wxConfig.getAppId())
					+"&grant_type=refresh_token"
					+"&refresh_token="+refreshToken;
			
			String resStr=WxHttp.httpsRequest(requestUrl, null);
			
			return WxJson.fromJson(resStr, Map.class);
		} catch (Exception e) {
			log.error("", e);
		}
		
		return null;
	}
	
	/**
	 * 拉取用户信息<br>
	 * <br>  
	 * 创建人：邓强   <br>
	 * 创建时间：2017年10月30日 上午11:12:28    <br> 
	 * 修改人：  <br>
	 * 修改时间：2017年10月30日 上午11:12:28   <br>  
	 * 修改备注：     <br> 
	 * @param openId
	 * @param lang	国家地区语言版本，zh_CN 简体，zh_TW 繁体，en 英语
	 * @return
	 */
	public static Map<String, Object> userInfo(String openId, String lang){
		WxConfig wxConfig =  TokenFactory.getDefaultWxConfigs();
		return userInfo(wxConfig, openId, lang);
	}

	/**
	 * 拉取用户信息<br>
	 * <br>  
	 * 创建人：邓强   <br>
	 * 创建时间：2017年10月30日 上午11:12:37    <br> 
	 * 修改人：  <br>
	 * 修改时间：2017年10月30日 上午11:12:37   <br>  
	 * 修改备注：     <br> 
	 * @param wxConfig
	 * @param openId
	 * @param lang	国家地区语言版本，zh_CN 简体，zh_TW 繁体，en 英语
	 * @return
	 */
	public static Map<String, Object> userInfo(WxConfig wxConfig, String openId, String lang){
		String accessToken = TokenFactory.getToken(wxConfig);
		try {
			if(lang==null){
				lang="zh_CN";
			}
			
			String requestUrl="https://api.weixin.qq.com/sns/userinfo"
					+"?access_token="+accessToken
					+"&openid="+openId
					+"&lang="+lang;
			
			String resStr=WxHttp.httpsRequest(requestUrl, null);
//			log.info(resStr);
			return WxJson.fromJson(resStr, Map.class);
		} catch (Exception e) {
			log.error("", e);
		}
		
		return null;
	}
	
	private static Set<String> ipSet=new HashSet<String>();
	
	/**
	 * 是否微信ip<br>
	 * <br>  
	 * 创建人：邓强   <br>
	 * 创建时间：2017年10月30日 上午11:13:25    <br> 
	 * 修改人：  <br>
	 * 修改时间：2017年10月30日 上午11:13:25   <br>  
	 * 修改备注：     <br> 
	 * @param ip
	 * @return
	 */
	public static boolean isWxip(String ip){
		WxConfig wxConfig =  TokenFactory.getDefaultWxConfigs();
		return isWxip(wxConfig, ip);
	}
	
	/**
	 * 是否微信ip<br>
	 * <br>  
	 * 创建人：邓强   <br>
	 * 创建时间：2017年10月30日 上午11:13:37    <br> 
	 * 修改人：  <br>
	 * 修改时间：2017年10月30日 上午11:13:37   <br>  
	 * 修改备注：     <br> 
	 * @param wxConfig
	 * @param ip
	 * @return
	 */
	public static boolean isWxip(WxConfig wxConfig,  String ip){
		String accessToken = TokenFactory.getToken(wxConfig);
		if(ipSet.contains(ip)){
			return true;
		}
		
		try {
			String requestUrl="https://api.weixin.qq.com/cgi-bin/getcallbackip?access_token="+accessToken;
			String resStr=WxHttp.httpsRequest(requestUrl, null);
			Map<String, Object> resMap=WxJson.fromJson(resStr, Map.class);
			if(resMap.get("ip_list")!=null){
				List<String> ipList=(List<String>)resMap.get("ip_list");
				for(String ipStr:ipList){
					ipSet.add(ipStr);
				}
			}
		} catch (Exception e) {
			log.error("", e);
		}
		
		return ipSet.contains(ip);
	}
}
